


module ip_rx#(
    parameter   SOURCE_IP       = {8'd192,8'd192,8'd7,8'd11             },
    parameter   SOURCE_IP_MASK  = {8'd255,8'd255,8'd255,8'd0            }          
   

)(
    input                       i_clk                                   ,
    input                       i_rst                                   ,
    input                       i_set_source_ip_valid                   ,
    input                       i_set_source_ip_mask                    ,
    input   [31: 0]             i_set_source_ip                         ,
    output                      m_axis_tvalid                           ,
    output  [7 : 0]             m_axis_tdata                            ,
    output                      m_axis_tlast                            ,
    output  [71: 0]             m_axis_tuser                            ,
    input                       s_axis_tvalid                           ,
    input   [7 : 0]             s_axis_tdata                            ,
    input                       s_axis_tlast                            ,
    input   [32: 0]             s_axis_tuser                            
);

    logic   [31: 0]             set_source_ip                           ;
    logic   [31: 0]             set_source_ip_mask                      ;
    logic   [31: 0]             ip_broadcast_addr                       ;
    logic                       ip_user_axis_rx_valid                   ;
    logic   [7 : 0]             ip_user_axis_rx_data                    ;
    logic                       ip_user_axis_rx_last                    ;
    logic   [71: 0]             ip_user_axis_rx_user                    ;
    logic                       ip_axis_rx_valid                        ;
    logic   [7 : 0]             ip_axis_rx_data                         ;
    logic                       ip_axis_rx_last                         ;
    logic   [32: 0]             ip_axis_rx_user                         ;
    logic   [15: 0]             rx_cnt                                  ;
    logic   [15: 0]             rx_check_sum                            ;
    logic   [15: 0]             ip_pkg_id                               ;
    logic   [7 : 0]             ip_pkg_type                             ;
    logic   [15: 0]             ip_pkg_len                              ;
    logic   [31: 0]             ip_rx_source_ip                         ;
    logic   [31: 0]             ip_rx_target_ip                         ;
    logic                       ip_rx_addr_access                       ;
    logic                       ip_rx_is_broadcast                      ;

    //  ila128_bit ila128_bit_ip_rx(
    //     .clk    ( i_clk),
    //     .probe0 ( {s_axis_tvalid,s_axis_tdata,s_axis_tlast,s_axis_tuser,rx_cnt,ip_rx_addr_access,
    //     ip_pkg_type,ip_pkg_len,ip_rx_is_broadcast,m_axis_tvalid,m_axis_tlast,m_axis_tdata})

    // );

    assign ip_broadcast_addr = set_source_ip | ~set_source_ip_mask;
    
    assign ip_rx_addr_access = ip_rx_target_ip  == set_source_ip ? 1 : 0;
    assign ip_rx_is_broadcast = ip_rx_source_ip == ip_broadcast_addr ? 1 : 0;

    assign  m_axis_tvalid = ip_user_axis_rx_valid;
    assign  m_axis_tdata = ip_user_axis_rx_data;
    assign  m_axis_tlast = ip_user_axis_rx_last;
    assign  m_axis_tuser = ip_user_axis_rx_user;
    
    always_ff @(posedge i_clk) begin
        if(i_rst) 
            set_source_ip <= SOURCE_IP;
        else if(i_set_source_ip_valid)
            set_source_ip <= i_set_source_ip;
        else    
            set_source_ip <= set_source_ip;
    end

    always_ff @(posedge i_clk) begin
        if(i_rst) 
            set_source_ip_mask <= SOURCE_IP_MASK;
        else if(i_set_source_ip_valid)
            set_source_ip_mask <= i_set_source_ip_mask;
        else    
            set_source_ip_mask <= set_source_ip_mask;
    end


    always_ff @(posedge i_clk) begin
        if(i_rst) begin
            ip_axis_rx_valid <= 0;
            ip_axis_rx_data  <= 0;
            ip_axis_rx_last  <= 0;
            ip_axis_rx_user  <= 0;
            
        end 
        else begin
            ip_axis_rx_valid <= s_axis_tvalid;
            ip_axis_rx_data  <= s_axis_tdata ;
            ip_axis_rx_last  <= s_axis_tlast ;
            ip_axis_rx_user  <= s_axis_tuser ;
        end
    end

    always_ff @(posedge i_clk) begin
        if(i_rst)
            rx_cnt <= 0;
        else if(ip_axis_rx_valid)
            rx_cnt <= rx_cnt + 1;
        else 
            rx_cnt <= 0;
    end

    always_ff @(posedge i_clk) begin
        if(i_rst)
            ip_pkg_len <= 0;
        else if(rx_cnt >= 2 && rx_cnt <= 3 && ip_axis_rx_valid)
            ip_pkg_len <= {ip_pkg_len[7 :0],ip_axis_rx_data};
        else 
            ip_pkg_len <= ip_pkg_len;
    end
     
    always_ff @(posedge i_clk) begin
        if(i_rst)
            ip_pkg_id <= 'd0;
        else if(rx_cnt >= 4 && rx_cnt <= 5 && ip_axis_rx_valid)   
            ip_pkg_id <= {ip_pkg_id[7 :0],ip_axis_rx_data};
        else 
            ip_pkg_id <= ip_pkg_id;
    end 
        
    always_ff @(posedge i_clk) begin
        if(i_rst)
            ip_pkg_type <= 0;
        else if(rx_cnt == 9 && ip_axis_rx_valid)
            ip_pkg_type <= ip_axis_rx_data;
        else 
            ip_pkg_type <= ip_pkg_type;
    end

    always_ff @(posedge i_clk) begin
        if(i_rst)
            rx_check_sum <= 0;
        else if(rx_cnt >= 10 && rx_cnt <= 11 && ip_axis_rx_valid)
            rx_check_sum <= ip_axis_rx_data;
        else 
            rx_check_sum <= rx_check_sum;
    end
             
    always_ff @(posedge i_clk) begin
        if(i_rst)
            ip_rx_source_ip <= 0;
        else if(rx_cnt >= 12 && rx_cnt <= 15 && ip_axis_rx_valid)
            ip_rx_source_ip <= {ip_rx_source_ip[23:0],ip_axis_rx_data};
        else 
            ip_rx_source_ip <= ip_rx_source_ip;
    end

    always_ff @(posedge i_clk) begin
        if(i_rst)
            ip_rx_target_ip <= 'd0;
        else if(rx_cnt >= 16 && rx_cnt <= 19 && ip_axis_rx_valid)
            ip_rx_target_ip <= {ip_rx_target_ip[23:0],ip_axis_rx_data};
        else 
            ip_rx_target_ip <= ip_rx_target_ip;
    end   
 
    always_ff @(posedge i_clk) begin
        if(i_rst)
            ip_user_axis_rx_data <= 0;
        else    
            ip_user_axis_rx_data <= ip_axis_rx_data;
    end
 
    always_ff @(posedge i_clk) begin
        if(i_rst)
            ip_user_axis_rx_user <= 0;
        else
            ip_user_axis_rx_user <= {ip_pkg_id, ip_rx_source_ip, ip_pkg_type, ip_pkg_len-16'd20};
    end
    
    always_ff @(posedge i_clk) begin
        if(i_rst)
            ip_user_axis_rx_last <= 0;
        else if(rx_cnt == ip_pkg_len && ip_user_axis_rx_last && ip_user_axis_rx_valid)
            ip_user_axis_rx_last <= 0;
        else if(rx_cnt == ip_pkg_len - 1 && ip_user_axis_rx_valid)
            ip_user_axis_rx_last <= 1;
        else 
            ip_user_axis_rx_last <= ip_user_axis_rx_last;
    end

    always_ff @(posedge i_clk) begin
        if(i_rst)
            ip_user_axis_rx_valid <= 0;
        //else if(ip_user_axis_rx_last & ip_user_axis_rx_valid)
        else if(rx_cnt == ip_pkg_len && ip_user_axis_rx_valid)
            ip_user_axis_rx_valid <= 0;
        else if((ip_rx_addr_access || ip_rx_is_broadcast) && rx_cnt == 20 && ip_axis_rx_user[31:16] == 16'h0800)
            ip_user_axis_rx_valid <= 1;
        else 
            ip_user_axis_rx_valid <= ip_user_axis_rx_valid;
    end

endmodule
